﻿// Copyright (c) 2009, Tom Lokovic
// All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

using Utils.Documentation;

namespace Byond.Midi
{
	/// <summary>
	/// Base class for all MIDI messages.
	/// </summary>
	[Doc]
	public abstract class MidiMessage
	{
		/// <remarks>
		/// Returns null if the value could not be parsed.
		/// </remarks>
		public static MidiMessage TryCreateFromByte(byte[] data, int deltaFrames)
		{
			// http://computermusicresource.com/MIDI.Commands.html

			if (data.Length == 0)
				return null;

			var bit0 = data[0];
			var bit1 = data.Length >= 2 ? data[1] : (byte)0;
			var bit2 = data.Length >= 3 ? data[2] : (byte)0;

			if (bit0 >= 128 && bit0 <= 143)
				return new NoteOffMessage(bit0 - 128, bit1, bit2, -1, deltaFrames);
			if (bit0 >= 144 && bit0 <= 159)
				return new NoteOnMessage(bit0 - 144, bit1, bit2, -1, deltaFrames);
			if (bit0 >= 176 && bit0 <= 191)
				return new ControlChangeMessage(bit0 - 176, bit1, bit2, -1, deltaFrames);

			return null;
		}

		protected MidiMessage(int midiDeviceNumber, int hostDeltaFrames)
		{
			MidiDeviceNumber = midiDeviceNumber;
			HostDeltaFrames = hostDeltaFrames;
		}

		public int MidiDeviceNumber { get; private set; }

		public int HostDeltaFrames { get; private set; }

		public abstract byte[] ToByte();

		public override string ToString()
		{
			return GetType().Name + " - DevNr: " + MidiDeviceNumber + " Frames: " + HostDeltaFrames;
		}
	}
}